#include "copyright.h"
#include "system.h"
#include "random.h"
#include <iostream>
#ifdef CHANGED
#include "synch.h"
#endif

using namespace std;

#define numberOfCustomers 1000//at least 30
#define numberOfCashiers 3 // 1-5
#define numberOfSalesmanA 1// 1-3
#define numberOfSalesmanB 2 
#define numberOfSalesmanC 2
#define numberOfSalesmanD 2
#define numberOfSalesmanE 2 
#define numberOfDepartments 5 //1-5
#define numberOfGoodsLoaders 5 // 1-5
#define minNumberOfItems    10000//bounds for random number generator for eachdept
#define maxNumberOfItems  15000


int numberOfSalesman[numberOfDepartments];
int initialSalesman[numberOfDepartments];




//GLOBAL VARIABLES
int privelegedLineCount =0;
int cashierLineCount = 0;
int salesManALineCount = 0;
int salesManBLineCount = 0;
int salesManCLineCount = 0;
int salesManDLineCount = 0;
int salesManELineCount = 0;
int totalSales;
int activeCustomers;
int test[11];

struct trolly {
  int custNum;
  int items[10];
} trolly_buffer[numberOfCustomers];

struct restockRequest {
int CustNum;
int myDept;
int requestedItem;
bool needHelp;
int goodsLoaderHandler;
int salesHandler;
bool glFinished;
bool needsGL;

}waitingForRestock[numberOfCustomers];


//GLOBAL LOCKS

Lock* initializeLock;
Lock* privelegedLineLock;
Lock* cashierLineLock;
Lock* cashierLock[numberOfCashiers];
Lock* customerLock[numberOfCustomers];
Lock* managerLock;
Lock* totalSalesLock;
Lock* returnsLock;
Lock* goodsLoaderLock[numberOfGoodsLoaders];
Lock* storeRoomLock;
Lock* deptItemLock[5];
Lock* deptLineLock[5];
Lock* operationalLineLock;
Lock* trollyLineLock;
Lock* salesmanLock[numberOfDepartments][5];
Lock* departmentLock[numberOfDepartments];
Lock* generatorLock;
Lock* GLLock;


//OTHER GLOBAL VARIABLES
int salesmanNumOfCustomers[numberOfDepartments][5];
bool OperationalLine[numberOfCashiers];
Lock* custSalesLock = new Lock("CustSales");
Condition* custWaitingCV;
Condition* salesWaitingCV;
bool ReadySalesman[numberOfDepartments][5];
bool OnBreak[numberOfCashiers];//Cashiers on break
bool priveleged[numberOfCustomers];//number of priveleged of  DIFED
int privelegedLineLengths[numberOfCashiers];//number of lines
int cashLineLengths[numberOfCashiers];//number of lines
List *privelegedLinesList[numberOfCashiers];//array of lists of customers in lines
List *cashierLinesList[numberOfCashiers];//array of lists of customers in lines
trolly trollyArray[numberOfCustomers];// global trolly list
bool enoughMoney[numberOfCustomers];//if the cust has enough money
bool custNeedHelp[numberOfCustomers];//if the cust doenst have enough money to signal manager
int customerMoney[numberOfCustomers];//amount of Money customers have
bool priv;//deciding whether or not a privledged customer
bool returns[numberOfCustomers];//if a customer is returning or not
int numberOfItemsReturns;//number of total items returned for restocking
bool CustomerFinished[numberOfCustomers];
bool GoodsLoaderBusy[numberOfGoodsLoaders];//if a goods loader is helping someone
bool usingStockRoom[numberOfGoodsLoaders];//it a goods loader is in the stockroom
int cashierHelpingCustomer[numberOfCustomers];//the cashier num who is helping a cust
int cashTotal[numberOfCashiers];//amount of money collected by each cashier
bool salesOnBreak[numberOfDepartments][5];//true if salesman is on break
bool cashBusy[numberOfCashiers];


List *deptLineList[5];//line list for departments

int deptItems[5][10];//items present in each dept
bool deptItemsNeedRestock[5];//if there needs to be an item restocked in a dept
List *waitingForRestockList[numberOfDepartments];//list of customers waiting for restock in a dept


int deptLineLength[5];
int totalSalesman;

//GLOBAL CONDITIONS
Condition *CustomerCondition[numberOfCustomers];
Condition *CashierCondition[numberOfCashiers];
Condition *GoodsLoadersCondition[numberOfGoodsLoaders];
Condition *ManagerCondition;
Condition *SalesmanCondition[numberOfDepartments][5];

//tells the salesman what number he is within a specific department
int SalesmanGenerator(int deptNum){

initialSalesman[deptNum]++;


return initialSalesman[deptNum];




}



//interaction code for the cashier
void Cashier(int CashNum){
int totalCustCost = 0;



bool Break=false;
if(!test[1]){
while(true){ 

cashierLock[CashNum]->Acquire();

//if my line size is zero
////printf(" Cashier %d Line Size is %d\n",CashNum, cashLineLengths[CashNum]);
if(OnBreak[CashNum==true]){
Break=true;
operationalLineLock->Acquire();
OperationalLine[CashNum]=false;
operationalLineLock->Release();
while(privelegedLineLengths[CashNum]>0){
//tell cust to leave line
int *currentCustomerNumber = (int*)privelegedLinesList[CashNum]->Remove();
privelegedLineLengths[CashNum]--;

CustomerCondition[*currentCustomerNumber]->Signal(cashierLock[CashNum]);}


while(cashLineLengths[CashNum]>0){
//tell cust to leave line
int *currentCustomerNumber = (int*)cashierLinesList[CashNum]->Remove();
cashLineLengths[CashNum]--;

CustomerCondition[*currentCustomerNumber]->Signal(cashierLock[CashNum]);}




CashierCondition[CashNum]->Wait(cashierLock[CashNum]);


}

else{//im not on break
Break=false;
OnBreak[CashNum]=false;
}
if(Break==false){
        cashierLineLock->Acquire();

        if(privelegedLineLengths[CashNum] > 0 && cashBusy[CashNum] == false){

        //get cust from line
        int *currentCustomerNumber = (int*)privelegedLinesList[CashNum]->Remove();
        privelegedLineLengths[CashNum]--;
        cashBusy[CashNum] = true;
        //printf("Cashier # %d is serving priveleged Customer # %d\n", CashNum, *currentCustomerNumber);

        //find customer trolly
        int trollyNumber = *currentCustomerNumber;


                if(returns[*currentCustomerNumber]){
                cashierLineLock->Release();

                for(int i = 0; i<10;i++){//return all items in the customers trolly
                if(trollyArray[trollyNumber].items[i] >0){
                //printf("Customer %d is returning %d of item %d \n",*currentCustomerNumber,trollyArray[trollyNumber].items[i],i);
                returnsLock->Acquire();
                numberOfItemsReturns += trollyArray[trollyNumber].items[i];
                returnsLock->Release();
                }


                }

                enoughMoney[*currentCustomerNumber] = true;

                }

        else{
                cashierLineLock->Release();

        totalCustCost = 0;
        int totalTrolly = 0;
 
 
 for(int i =0; i<10; i++)
 totalTrolly += trollyArray[trollyNumber].items[i];
 
 
 if(test[4])
 printf("TEST 4: CUSTOMER [%d] HAS [%d] NUMBER OF ITEMS IN TROLLY\n", *currentCustomerNumber,totalTrolly);
 
 int temp = 0;
for(int i = 0; i< 10; i++){
        totalCustCost += trollyArray[trollyNumber].items[i] * (i + 1);
                temp = 0;
        temp += trollyArray[trollyNumber].items[i];
                if(test[4]){
                totalTrolly = totalTrolly - temp;
                
                printf("TEST 4: CASHIER [%d] REMOVING ITEM [%d] TOTAL IN TROLLY NOW = [%d]\n", CashNum,i,totalTrolly);
                }
                
        if(priveleged[*currentCustomerNumber] == true){
        
        for(int j = 0; j < trollyArray[trollyNumber].items[i]; j++)
        printf("Cashier [%d] got [%d] from trolly of PrivilegedCustomer [%d].\n",CashNum,i,*currentCustomerNumber);
        }
        
        else{
        for(int j = 0; j < trollyArray[trollyNumber].items[i]; j++)
        printf("Cashier [%d] got [%d] from trolly of Customer [%d].\n",CashNum,i,*currentCustomerNumber);
        }
}
if(test[4])
printf("TEST 4: CASHIER [%d] HAS REMOVED ALL ITEMS FROM CUSTOMER [%d]", CashNum,*currentCustomerNumber);

}
 
 
 if(priveleged[*currentCustomerNumber] == true)
printf("Cashier [%d] tells PrivilegedCustomer [%d] total cost is $[%d]\n",CashNum,*currentCustomerNumber,totalCustCost);
else
printf("Cashier [%d] tells Customer [%d] total cost is $[%d]\n",CashNum,*currentCustomerNumber,totalCustCost);

CustomerCondition[*currentCustomerNumber]->Signal(cashierLock[CashNum]);//tell cust to figure out if he has enough money
CashierCondition[CashNum]->Wait(cashierLock[CashNum]);

if(enoughMoney[*currentCustomerNumber] == true){
printf("Manager emptied Counter [%d] drawer.\n",CashNum);
cashTotal[CashNum] += totalCustCost;

totalSalesLock->Acquire();//krump
printf("Manager has total sale of $[%d].\n",totalSales);
if(test[7])
printf("TEST 7: TOTAL SALES IS UPDATED TO $%d", totalSales);

totalSalesLock->Release();//krump

printf("Cust %d has enough money... Giving Receipt",*currentCustomerNumber);
CustomerCondition[*currentCustomerNumber]->Signal(cashierLock[CashNum]);
CustomerFinished[*currentCustomerNumber]=true;
cashBusy[CashNum] = false;

}
else{

custNeedHelp[*currentCustomerNumber] = true;
CustomerCondition[*currentCustomerNumber]->Signal(cashierLock[CashNum]);
CustomerFinished[*currentCustomerNumber]=true;
cashBusy[CashNum] = false;


}




}
else{
                cashierLineLock->Acquire();

if(cashLineLengths[CashNum] > 0 && cashBusy[CashNum] == false){

//get cust from line
int *currentCustomerNumber = (int*)cashierLinesList[CashNum]->Remove();
cashLineLengths[CashNum]--;
cashBusy[CashNum] = true;
//printf("Cashier # %d is serving Customer # %d\n", CashNum, *currentCustomerNumber);

//find customer trolly
int trollyNumber = *currentCustomerNumber;

                if(returns[*currentCustomerNumber]){
                                cashierLineLock->Release();

                for(int i = 0; i<10;i++){//return all items in the customers trolly
                if(trollyArray[trollyNumber].items[i] >0){
                //printf("Customer %d is returning %d of item %d \n",*currentCustomerNumber,trollyArray[trollyNumber].items[i],i);
                returnsLock->Acquire();
                numberOfItemsReturns += trollyArray[trollyNumber].items[i];
                returnsLock->Release();
                }


                }

                enoughMoney[*currentCustomerNumber] = true;


                }

else{

                cashierLineLock->Release();

totalCustCost = 0;
for(int i = 0; i< 10; i++){
        totalCustCost += trollyArray[trollyNumber].items[i] * (i + 1);
         if(priveleged[*currentCustomerNumber] == true){
        
        for(int j = 0; j < trollyArray[trollyNumber].items[i]; j++)
        printf("Cashier [%d] got [%d] from trolly of PrivilegedCustomer [%d].\n",CashNum,i,*currentCustomerNumber);
        }
        
        else{
        for(int j = 0; j < trollyArray[trollyNumber].items[i]; j++)
        printf("Cashier [%d] got [%d] from trolly of Customer [%d].\n",CashNum,i,*currentCustomerNumber);
        }
}


}
 
 
 if(priveleged[*currentCustomerNumber] == true)
printf("Cashier [%d] tells PrivilegedCustomer [%d] total cost is $[%d]\n",CashNum,*currentCustomerNumber,totalCustCost);
else
printf("Cashier [%d] tells Customer [%d] total cost is $[%d]\n",CashNum,*currentCustomerNumber,totalCustCost);

CustomerCondition[*currentCustomerNumber]->Signal(cashierLock[CashNum]);
////printf("Cashier # %d waiting",CashNum);
CashierCondition[CashNum]->Wait(cashierLock[CashNum]);

if(enoughMoney[*currentCustomerNumber] == true){
if(priveleged[*currentCustomerNumber] == true)
printf("Cashier [%d] got money $[%d] from PrivilegedCustomer [%d].\n",CashNum,totalCustCost,*currentCustomerNumber);
else
printf("Cashier [%d] got money $[%d] from Customer [%d].\n",CashNum,totalCustCost,*currentCustomerNumber);

CustomerCondition[*currentCustomerNumber]->Signal(cashierLock[CashNum]);
CustomerFinished[*currentCustomerNumber]=true;
}
else{
if(priveleged[*currentCustomerNumber] == true){
printf("Cashier [%d] asks PrivilegedCustomer [%d] to wait for Manager.\n",CashNum,*currentCustomerNumber);
printf("Cashier [%d] informs the Manager that PrivilegedCustomer [%d] does not have enough money.\n",CashNum,*currentCustomerNumber);
}
else{
printf("Cashier [%d] asks Customer [%d] to wait for Manager.\n",CashNum,*currentCustomerNumber);
printf("Cashier [%d] informs the Manager that Customer [%d] does not have enough money.\n",CashNum,*currentCustomerNumber);
}

custNeedHelp[*currentCustomerNumber] = true;
CustomerCondition[*currentCustomerNumber]->Signal(cashierLock[CashNum]);
CustomerFinished[*currentCustomerNumber]=true;
cashBusy[CashNum] = false;


}




}

else{//if he has nothing to do then its time to wait
                cashierLineLock->Release();

//printf("Cashier %d line empty going to halt\n", CashNum);
cashBusy[CashNum] = false;
if(privelegedLineLengths[CashNum] == 0 && cashLineLengths[CashNum] ==0)
CashierCondition[CashNum]->Wait(cashierLock[CashNum]);

}
cashierLock[CashNum]->Release();

}
                cashierLineLock->Release();

cashierLock[CashNum]->Release();

}
                cashierLineLock->Release();

cashierLock[CashNum]->Release();


}}




}

void Manager(int ManNum){




ManagerCondition->Wait(managerLock);
while(true){
managerLock->Acquire();
//collect total sales



totalSalesLock->Acquire();//krump
printf("-------Total Sale of the entire store until now is $[%d]---------\n",totalSales);
if(test[7])
printf("TEST 7: TOTAL SALES IS UPDATED TO $%d", totalSales);
totalSalesLock->Release();//krump

/*
*** put salesman on break *******
for(int i = 0;i<numberOfDepartments;i++){
        for(int j = 0; j < numberOfSalesman[i]; j++){
                 if(salesOnBreak[i][j] == true)
                                salesOnBreak[i][j] = false;
                                printf("Manager sends DepartmentSalesman [%d] of Department [%d] on break. \n",j,i);
                                 }
  }
bool breakcode = false;
for(int i = 0;i<numberOfDepartments;i++){
        for(int j = 0; j < numberOfSalesman[i]; j++){
                 if(salesOnBreak[i][j] == false){
                                salesOnBreak[i][j] = true;breakcode = true;
                                printf("Manager brings back DepartmentSalesman [%d] of Department [%d] from break. \n",j,i);
                                break;
                                 }}
         if(breakcode = true)
            break;
  }


*******put cashiers on break******/
/*
operationalLineLock->Acquire();
//RANDOM
for(int i = 0; i < numberOfCashiers;i++){
if(OnBreak[i] == true){
printf("Cashier [%d] was called from break by Manager to work.\n",i);
printf("Manager brings back Cashier [%d] from break.\n",i);

if(test[5])
printf("TEST 5: CASHIER %d IS BEING TAKEN OFF BREAK \n", i);

OnBreak[i] = false;
OperationalLine[i] = true;
CashierCondition[i]->Signal(cashierLock[i]);
break;
}
}

int rando;
  

  rando = GetRand(0, numberOfCashiers-1);
  //printf(" Puttin Cashier %d  to break \n" ,rando);
OnBreak[rando]=true;
OperationalLine[rando] = false;
printf("Cashier [%d] is going on break.\n",rando);
printf("Manager sends Cashier [%d] on break.\n",rando);

if(test[5])
printf("TEST 5: CASHIER %d IS GOING BREAK\n", rando);
if(test[6])
printf("TEST 6: CASHIER %d IS GOING BREAK\n", rando);


for (int i = 0; i<numberOfCashiers;i++){
if(((privelegedLineLengths[i] + cashLineLengths[i]) >=3 ) && OnBreak[i]==true){
printf("Cashier [%d] was called from break by Manager to work.\n",i);
printf("Manager brings back Cashier [%d] from break.\n",i);
OnBreak[i] = false;
OperationalLine[i] = true;
CashierCondition[i]->Signal(cashierLock[i]);
if(test[6])
printf("TEST 6: CASHIER %d IS WAKING UP DUE TO LINE LENGTH GREATER THAN 3 \n", i);
}
}

operationalLineLock->Release();
*/


//help customers who dont have enough money


int helpingCustNumber;
bool helpingCustomer = false;

for(int i = 0; i < numberOfCustomers; i++){
if(custNeedHelp[i] == true){
printf("Manager got a call from Cashier [%d].\n",cashierHelpingCustomer[i]);
helpingCustNumber = i;
helpingCustomer = true;
break;
}
}
//if(helpingCustNumber != -1){
if(test[2] ){
printf("TEST 2: MANAGER TALKING TO CASHIER [%d]\n",cashierHelpingCustomer[helpingCustNumber]);
printf("TEST 2: MANAGER DONE TALKING TO CASHIER [%d]\n",cashierHelpingCustomer[helpingCustNumber]);
}

if(test[2])
printf("TEST 2: MANAGER TALKING TO CUSTOMER [%d]\n", helpingCustNumber);


while(helpingCustomer == true){
//printf("Manager is helping Customer %d to remove items\n",helpingCustNumber);
//the amount money cust has
//total cost
int totalCustCost = 0;
for(int i = 0; i< 10; i++){
        totalCustCost += trollyArray[helpingCustNumber].items[i] * (i + 1);
        
}

if(totalCustCost > customerMoney[helpingCustNumber]){//if cust has enough money
for(int i = 9; i>-1; i--){
   if(trollyArray[helpingCustNumber].items[i] > 0){
        trollyArray[helpingCustNumber].items[i]--;
        if(priveleged[helpingCustNumber] == true){
        printf("PrivilegedCustomer [%d] tells Manager to remove [%d] from trolly.\n", helpingCustNumber,i);
        printf("Manager removes [%d] from the trolly of PrivilegeCustomer [%d].\n",i,helpingCustNumber);
        }
        else{
        printf("Customer [%d] tells Manager to remove [%d] from trolly.\n", helpingCustNumber,i);
        printf("Manager removes [%d] from the trolly of Customer [%d].\n",i,helpingCustNumber);
        }
        
        //recalculate cost
         totalCustCost = 0;
        for(int j = 0; j< 10; j++){
        totalCustCost += trollyArray[helpingCustNumber].items[j] * (j + 1);}
        //see if customer now has enough money
        //printf("Customer %d has $%d and the cost is $%d\n", helpingCustNumber,customerMoney[helpingCustNumber],totalCustCost);
        if(totalCustCost <= customerMoney[helpingCustNumber])
        break;
        else
        i++;
}}}

 if(priveleged[helpingCustNumber] == true){
printf("PrivilegedCustomer [%d] pays [%d] to Manager after removing items and is waiting for receipt from Manager.\n", helpingCustNumber,totalCustCost);
printf("Manager gives receipt to PrivilegeCustomer [%d].\n",helpingCustNumber);
}
else{
printf("Customer [%d] pays [%d] to Manager after removing items and is waiting for receipt from Manager.\n", helpingCustNumber,totalCustCost);
printf("Manager gives receipt to Customer [%d].\n",helpingCustNumber);
}

totalSalesLock->Acquire();//update final cost
totalSales += totalCustCost;//krump
if(test[7])
printf("TEST 7: TOTAL SALES IS UPDATED TO $%d", totalSales);
totalSalesLock->Release();//krump

//tell cust to get back in line
helpingCustomer = false;
custNeedHelp[helpingCustNumber] = false;
enoughMoney[helpingCustNumber] == true;

CustomerCondition[helpingCustNumber]->Signal(managerLock);

if(test[2])
printf("TEST 2: MANAGER DONE TALKING TO CUSTOMER [%d]\n", helpingCustNumber);

for(int i = 0; i < numberOfCustomers; i++){//find a customer that needs help
if(custNeedHelp[i] == true){
helpingCustNumber = i;
helpingCustomer = true;
break;
}
}
//}

}


ManagerCondition->Wait(managerLock);
managerLock->Release();

}
}


//interaction code for the customer
void Customer(int CustNum){

//****cust returns
//if cust return array value = true 
//they get in line for cashier
//cashier checks boolean 
//if returning then empty cust cart with print and send home
//keep array of items that are getting returned
//send cust home

int number=0;
initializeLock->Acquire();
int *custPointer = &CustNum;
int money = 150;
customerMoney[CustNum] = money;
bool finished = false;

trolly myCart;//create cart
//initialize to zero
for(int i = 0; i<10; i++){
myCart.items[i] = 0;

}
//myCart.items[0] = 5;
myCart.custNum = CustNum;
trollyArray[CustNum] = myCart;
initializeLock->Release();


if( ! test[1] ){

if(priveleged[CustNum] == true)
printf("PrivilegedCustomer [%d] enters the SuperMarket\n", CustNum);
else
printf("Customer [%d] enters the SuperMarket\n", CustNum);



//trollyLineLock->Acquire();
//printf("Customer %d getting in line for Trolly \n", CustNum);
//printf("Customer %d has secured Trolly\n",CustNum);
//trollyLineLock->Release();

int deptNum = GetRand(0, (numberOfDepartments-1));
int SalesmanNum=0;

//the items that the customer want to buy
int wishList[10];
int itemTotal = 0;
for(int i = 0; i < 10; i++){
int amount = GetRand(0,5);
wishList[i] = amount;
itemTotal += amount;
//printf("Cust %d wants %d of item %d \n", CustNum,amount,i);
}


//printf("I am Customer %d Getting in line %d\n",CustNum, deptNum);
//deptLineLock[deptNum]->Release();
for(int i=0; i<numberOfSalesman[deptNum]; i++){
        if(ReadySalesman[deptNum][i]==true){
        SalesmanNum=i;
 break;
 }
 }
 if(priveleged[CustNum] == true)
printf("PrivilegedCustomer [%d] wants to buy [%d] no.of items.\n",CustNum,itemTotal);
else
printf("Customer [%d] wants to buy [%d] no.of items.\n",CustNum,itemTotal);





if(priveleged[CustNum] == true){
for(int i = 0; i < 10; i++)
printf("PrivilegedCustomer [%d] wants to buy [%d]-[%d].\n",CustNum,i,wishList[i]);

printf("PrivilegedCustomer [%d] gets in line for a trolly\n",CustNum);
printf("PrivilegedCustomer [%d] has a trolly for shopping\n",CustNum);
printf("PrivilegedCustomer [%d] wants to shop in Department[%d]\n",CustNum,deptNum);
printf("PrivilegedCustomer [%d] is interacting with DepartmentSalesman[%d] of Department[%d]\n",CustNum,SalesmanNum,deptNum);
printf("PrivilegedCustomer [%d] gets in line for the Department [%d]\n",CustNum,deptNum);}

else{
for(int i = 0; i < 10; i++)
printf("Customer [%d] wants to buy [%d]-[%d].\n",CustNum,i,wishList[i]);

printf("Customer [%d] gets in line for a trolly\n",CustNum);
printf("Customer [%d] has a trolly for shopping\n",CustNum);
printf("Customer [%d] wants to shop in Department[%d]\n",CustNum,deptNum);
printf("Customer [%d] gets in line for the Department [%d]\n",CustNum,deptNum);
printf("Customer [%d] is interacting with DepartmentSalesman[%d] of Department[%d]\n",CustNum,SalesmanNum,deptNum);
}

        customerLock[CustNum]->Acquire();
        printf("Cust %d got salesman Lock\n", CustNum);
        
      deptLineLock[deptNum]->Acquire();

//randomly generate dep and get in
deptLineList[deptNum]->Append(custPointer);
deptLineLength[deptNum]++;
 deptLineLock[deptNum]->Release();
  SalesmanCondition[deptNum][SalesmanNum]->Signal(salesmanLock[deptNum][SalesmanNum]);
  
  
  printf("Cust %d is waiting on salesman\n", CustNum);
CustomerCondition[CustNum]->Wait(customerLock[CustNum]);


        printf("Customer [%d] has finished line in Department [%d]\n",CustNum,deptNum);


salesmanLock[deptNum][SalesmanNum]->Release();






deptItemLock[deptNum]->Acquire();

for(int i = 0; i < 10; i++){
if(wishList[i] > deptItems[deptNum][i]){

while(wishList[i] > deptItems[deptNum][i]){//if need restock
//update number of items in dep
if(priveleged[CustNum] == true)
 printf("PrivilegedCustomer [%d] is not able to find [%d] and is searching for DepartmentSalesman [%d].\n",CustNum,i,SalesmanNum);
else
 printf("Customer [%d] is not able to find [%d] and is searching for DepartmentSalesman [%d].\n",CustNum,i,SalesmanNum);
//salesmanNumOfCustomers[deptNum][SalesmanNum]++;
 if(test[8])
printf("TEST 8: CUSTOMER %d IS TAKING ITEM %d OFF SHELF IN DEPT %d\n", CustNum,i,deptNum);

wishList[i] -= deptItems[deptNum][i];
deptItems[deptNum][i] = 0;
//this code runs if the customer needs restocking
waitingForRestock[CustNum].needHelp = true;
waitingForRestock[CustNum].needsGL = true;
waitingForRestock[CustNum].CustNum = CustNum;
waitingForRestock[CustNum].requestedItem = i;
waitingForRestock[CustNum].myDept = deptNum;

salesmanLock[deptNum][SalesmanNum]->Acquire();
 deptItemsNeedRestock[deptNum] = true;
 //printf("Customer %d waiting for salesman \n", CustNum);
  SalesmanCondition[deptNum][SalesmanNum]->Signal(salesmanLock[deptNum][SalesmanNum]);
 //salesmanLock[deptNum][SalesmanNum]->Acquire();
salesmanLock[deptNum][SalesmanNum]->Release();
 

 printf("Customer [%d] is asking for assistance from DepartmentSalesman [%d] in Department [%d].\n",CustNum,SalesmanNum,deptNum);
  if(test[10])
  printf("TEST 10: CUSTOMER %d WAITING ON RESTOCK WITH SALESMAN %d\n",CustNum,SalesmanNum);
  
  deptItemLock[deptNum]->Release();
  
 CustomerCondition[CustNum]->Wait(salesmanLock[deptNum][SalesmanNum]);
//salesmanLock[deptNum][SalesmanNum]->Release();
 
 deptItemLock[deptNum]->Acquire();
 
 if(test[10])
  printf("TEST 10: CUSTOMER %d WAKING UP FROM RESTOCK WAIT\n",CustNum);
 
 printf("Customer [%d] has received assistance about restocking of [%d] from DepartmentSalesman [%d] in Department [%d].\n",CustNum,i,SalesmanNum,deptNum);
  waitingForRestock[CustNum].needHelp=false;
 deptItemsNeedRestock[deptNum] = false;
 
}
i--;
}
else{//the customer found enough of the item he wants
deptItems[deptNum][i] -= wishList[i];
deptItemLock[deptNum]->Release();
if(test[8])
printf("TEST 8: CUSTOMER %d IS TAKING ITEM %d OFF SHELF IN DEPT %d\n", CustNum,i,deptNum);
myCart.items[i]+=wishList[i];
if(priveleged[CustNum] == true)
printf("PrivilegedCustomer [%d] has found [%d] and placed [%d] in the trolly\n",CustNum,i,myCart.items[i]);
else
printf("Customer [%d] has found [%d] and placed [%d] in the trolly\n",CustNum,i,myCart.items[i]);


}
}
deptItemLock[deptNum]->Release();

trollyArray[CustNum] = myCart;
if(priveleged[CustNum] == true){
printf("PrivilegedCustomer [%d] has finished shopping in Department[%d]\n",CustNum,deptNum);
 
printf("PrivilegedCustomer [%d] is looking for the Cashier.\n",CustNum);}
else{
printf("Customer [%d] has finished shopping in Department[%d]\n",CustNum,deptNum);
 
printf("Customer [%d] is looking for the Cashier.\n",CustNum);}

}


// SECOND INTERACTION CODE******************** with cust/cashier
bool t1 = true;

while(CustomerFinished[CustNum]!=true && t1 == true){


cashierLineLock->Acquire();
if(priveleged[CustNum]==true){



operationalLineLock->Acquire();
//Find Shortest priveleged Line
int temp = 200;
number = 0;
for(int i = 0; i < numberOfCashiers; i++){

if(OperationalLine[i]==true)
//printf(" Line %d Operational\n", i);

if(test[1])
printf("Customer %d Checking privileged line number %d which has length of %d\n",CustNum, i,privelegedLineLengths[i]);

if ((privelegedLineLengths[i] < temp) && (OperationalLine[i]==true)){
        temp = privelegedLineLengths[i];
        number = i;
        
}
}
operationalLineLock->Release();
//printf("Going to priveleged Line # %d\n", number);
if(priveleged[CustNum] == true)
printf("PrivilegedCustomer [%d] chose Cashier [%d] with line of length [%d].\n",CustNum,number,privelegedLineLengths[number]);
else
printf("Customer [%d] chose Cashier [%d] with line of length [%d].\n",CustNum,number,privelegedLineLengths[number]);


privelegedLineLengths[number]++;

if(test[1])
printf("Size of priveleged line %d is now %d\n",number,privelegedLineLengths[number]);

privelegedLinesList[number]->Append(custPointer);

//cashierLock[number]->Acquire();
cashierLineLock->Release();


}

else{//else i am not priviliged and i look in other line

operationalLineLock->Acquire();
//Find Shortest Line
int temp = 200;
number = 0;
for(int i = 0; i < numberOfCashiers; i++){

if(test[1])
printf("Customer %d Checking line number %d which has length of %d\n",CustNum, i,cashLineLengths[i]);
if ((cashLineLengths[i] < temp) && (OperationalLine[i]==true)){
        temp = cashLineLengths[i];
        number = i;
        
}
}
operationalLineLock->Release();
//printf("Going to Line # %d\n", number);

printf("Customer [%d] chose Cashier [%d] with line of length [%d].\n",CustNum,number,cashLineLengths[number]);


cashLineLengths[number]++;

if(test[1])
printf("Size of line %d is now %d\n",number,cashLineLengths[number]);

cashierLinesList[number]->Append(custPointer);

cashierLineLock->Release();



}
cashierLock[number]->Acquire();

CashierCondition[number]->Signal(cashierLock[number]);

if(!test[1]){

//printf("Customer %d Im waiting on the Cashier\n", CustNum);
CustomerCondition[CustNum]->Wait(cashierLock[number]);//put myself to sleep and wait for cashier lock to open me up
//waiting for cash to finish scanning items
//printf("Customer %d woken up by cashier \n", CustNum);
int totalCustCost = 0;
for(int i = 0; i< 10; i++){
        totalCustCost += trollyArray[CustNum].items[i] * (i + 1);
        
       
}


cashierHelpingCustomer[CustNum] = number;

if(money >= totalCustCost){//find out if the cust needs help from manager
enoughMoney[CustNum] = true;

}
else{
enoughMoney[CustNum] = false;


}
CashierCondition[number]->Signal(cashierLock[number]);//telling cashier enough money variable is set
//CustomerCondition[CustNum]->Wait(cashierLock[number]);//wait for cashier to wake him up
managerLock->Acquire();
cashierLock[number]->Release();

if(enoughMoney[CustNum]==true)
custNeedHelp[CustNum]=false;
else
custNeedHelp[CustNum]=true;

if(custNeedHelp[CustNum] == false || returns[CustNum] == true){

if(priveleged[CustNum] == true)
printf("PrivilegedCustomer [%d] pays [%d] to Cashier [%d] and is now waiting for receipt.\n",CustNum,totalCustCost,number);
else
printf("Customer [%d] pays [%d] to Cashier [%d] and is now waiting for receipt.\n",CustNum,totalCustCost,number);

if(test[3])
printf("TEST 3: CUSTOMER [%d] IS NOT LEAVING UNTIL HE GETS RECEIPT\n",CustNum);






totalSalesLock->Acquire();//krump
totalSales += totalCustCost;//krump
if(test[7])
printf("TEST 7: TOTAL SALES IS UPDATED TO $%d\n", totalSales);
totalSalesLock->Release();//krump

managerLock->Acquire();
ManagerCondition->Signal(managerLock);
managerLock->Release();

finished = true;
}                                             
                   

if(custNeedHelp[CustNum] == true){

if(priveleged[CustNum] == true){

printf("PrivilegedCustomer [%d] cannot pay [totalCustCost]\n" , CustNum);
ManagerCondition->Signal(managerLock);
printf("PrivilegedCustomer [%d] is waiting for Manager for negotiations.\n",CustNum);
CustomerCondition[CustNum]->Wait(managerLock);
printf("Cashier [%d]/Manager gave the receipt to PrivilegedCustomer [%d] and tells him to leave.\n",number,CustNum);
}
else{
printf("Customer [%d] cannot pay [totalCustCost]\n" , CustNum);
ManagerCondition->Signal(managerLock);
printf("Customer [%d] is waiting for Manager for negotiations.\n",CustNum);
CustomerCondition[CustNum]->Wait(managerLock);
printf("Cashier [%d]/Manager gave the receipt to Customer [%d] and tells him to leave.\n",number,CustNum);
}


}
activeCustomers--;
printf("Customer [%d] got receipt from Cashier [%d]/Manager and is now leaving.\n",CustNum,number);
printf("ACTIVE CUSTOMERS = %d\n", activeCustomers);
if(activeCustomers == 0){

 for(int i = 0; i < numberOfCashiers; i++)
  printf("Total Sale from Counter [%d] is $[%d]. \n",i,cashTotal[i]);
  
  
  printf("Total Sale of the entire store is $[%d].\n",totalSales);

}

if(test[3]){
printf("TEST 3: CUSTOMER [%d] HAS RECEIPT AND IS LEAVING\n",CustNum);
printf("TEST 3: CASHIER [%d] SEES THAT CUSTOMER [%d] HAS LEFT\n", number, CustNum);
}

managerLock->Release();




}
t1 = false;
}




}







//interaction code for the goods loader
void GoodsLoader(int GLNum){
int rr;
GoodsLoadersCondition[GLNum]->Wait(GLLock);

while(true){
//printf("Hey I am GoodsLoader %d \n", GLNum);
//goodsLoaderLock[GLNum]->Acquire();
GLLock->Acquire();
//find restock request
////printf(" I am goodsloader %d \n" ,GLNum);

for(int j = 0; j <numberOfCustomers;j++){
////printf(" Waiting stock is %d \n" ,waitingForRestock[j].goodsLoaderHandler);
if(waitingForRestock[j].goodsLoaderHandler == GLNum)
rr = j;}

int DepartNum;

for(int i =0; i<numberOfCustomers; i++){
if(waitingForRestock[i].goodsLoaderHandler==GLNum &&  waitingForRestock[i].needsGL== true){
DepartNum=waitingForRestock[i].myDept;
waitingForRestock[i].needsGL=false;
printf(" Goodsloader [%d] setting his department to [%d] \n " , GLNum, DepartNum);
////printf("I am goods loader and Im being SETTT DEPARMENT WISE \n");
break;
}
}

//find out what item needs to be restocked
//check each dep
//GLLock->Acquire();
//printf("GoodsLoader [%d] is alive \n" , GLNum);
//printf("number of Salesman in department %d = %d \n", DepartNum, numberOfSalesman[DepartNum]);
//if(numberOfSalesman[DepartNum] != 0){//if dept exists
deptItemLock[DepartNum]->Acquire();
for( int i = 0; i<10; i++){
////printf("I am GoodsLoader %d and I am in Department %d and the amount of item %d is %d and my customer is %d \n",GLNum, DepartNum, i, deptItems[DepartNum][i], rr);

printf("GoodsLoader [%d] checks the amount of [%d] in department [%d] and it is [%d] \n" , GLNum, i, DepartNum, deptItems[DepartNum][i]);
if(deptItems[DepartNum][i] == 0){
printf("GoodsLoader [%d] is informed by DepartmentSalesman [%d] of Department [%d] to restock [%d]. \n",GLNum,waitingForRestock[rr].salesHandler,waitingForRestock[rr].myDept,i);




//it takes a little time to get to the storeroom
int amountOfTimeToWait = GetRand(1, 7);
/*
for(int j = 0;j<amountOfTimeToWait;j++){
currentThread->Yield();
}
*/
for(int j;j<numberOfGoodsLoaders;j++){
if (usingStockRoom[j] == true)
printf("GoodsLoader [%d] is waiting for GoodsLoader [%d] to leave the StockRoom.\n",GLNum,j);


}
//get storeroom lock
storeRoomLock->Acquire();
if(test[9])
printf("TEST 9: GOODS LOADER %d HAS ENTERED THE STOCK ROOM\n",GLNum);
usingStockRoom[GLNum] = true;
//get item from storeroom and restock
printf("GoodsLoader [%d] is in the StockRoom and got [%d].\n",GLNum,i);

if(test[8])
printf("TEST 8: GOODS LOADER %d IS RESTOCKING ITEM %d IN DEPT %d\n",GLNum,i,DepartNum);

deptItems[DepartNum][i]++;
printf("GoodsLoader [%d] has restocked [%d] in Department [%d].\n",GLNum,i,DepartNum);
//printf("Goods Loader %d has restocked one of item %d in Dept %d \n",GLNum,i,DepartNum);
printf("GoodsLoader [%d] leaves StockRoom.\n",GLNum);
usingStockRoom[GLNum] = false;

if(test[9])
printf("TEST 9: GOODS LOADER %d HAS LEFT THE STOCK ROOM\n",GLNum);

storeRoomLock->Release();




}

deptItemLock[DepartNum]->Release();
}

//}



deptItemsNeedRestock[waitingForRestock[rr].myDept] = false;
waitingForRestock[rr].glFinished = true;//notify salesman done
printf("Goods loader [%d] waiting or sending lock to Salesman [%d] of Department [%d] \n" ,GLNum, waitingForRestock[rr].salesHandler, waitingForRestock[rr].myDept);
salesmanLock[waitingForRestock[rr].myDept][waitingForRestock[rr].salesHandler]->Acquire();
SalesmanCondition[waitingForRestock[rr].myDept][waitingForRestock[rr].salesHandler]->Signal(salesmanLock[waitingForRestock[rr].myDept][waitingForRestock[rr].salesHandler]);
salesmanLock[waitingForRestock[rr].myDept][waitingForRestock[rr].salesHandler]->Release();

GoodsLoaderBusy[GLNum] = false;
printf("GoodsLoader [%d] is waiting for orders to restock.\n",GLNum);
GoodsLoadersCondition[GLNum]->Wait(GLLock);
}


}
//interaction code for the salesman
void Salesman(int deptNum){

generatorLock->Acquire();

int salesNum = SalesmanGenerator(deptNum);


generatorLock->Release();
printf("My line length is %d\n",deptLineLength[deptNum]);

if(deptLineLength[deptNum] == 0)
SalesmanCondition[deptNum][salesNum]->Wait(salesmanLock[deptNum][salesNum]);

////printf("Salesman %d Alive and Working Boss! Right-O \n", deptNum);
ReadySalesman[deptNum][salesNum]=true;
while(true){


 if(salesOnBreak[deptNum][salesNum] == false){ 

//get my line lock
salesmanLock[deptNum][salesNum]->Acquire();
printf("Salesman %d of Dept %d has his lock\n", salesNum,deptNum);
//deptLineLock[deptNum]->Acquire();

//see if anyone is in line...if so signal ONE to enter store
while(deptLineLength[deptNum] != 0){

int *currentCustomerNumber = (int*)deptLineList[deptNum]->Remove();
printf("DepartmentSalesman [%d] welcomes Customer/PrivilegeCustomer [%d] to Department [%d] now my line is [%d] long.\n",salesNum,*currentCustomerNumber,deptNum,deptLineLength[deptNum]-1);


customerLock[*currentCustomerNumber]->Acquire();
deptLineLength[deptNum]--;
CustomerCondition[*currentCustomerNumber]->Signal(customerLock[*currentCustomerNumber]);
customerLock[*currentCustomerNumber]->Release();
}

salesmanLock[deptNum][salesNum]->Release();

//release line lock

while(salesmanNumOfCustomers[deptNum][salesNum]>0){
salesmanLock[deptNum][salesNum]->Release();
int restockRequestNumber;
//get deptItemsneed restock lock

if(deptItemsNeedRestock[deptNum] == true){
departmentLock[deptNum]->Acquire();
//find restock request and set me as sales handler
for(int i = 0; i < numberOfCustomers; i++){
if( waitingForRestock[i].needHelp ==true && waitingForRestock[i].myDept == deptNum){
waitingForRestock[i].needHelp = false;
restockRequestNumber = i;
 break;
}}
bool GLFound=false;
//find a free goodsloader

while(GLFound !=true){
GLLock->Acquire();
departmentLock[deptNum]->Release();
departmentLock[deptNum]->Acquire();
int goodsloadernumber=0;
for(int i = 0; i < numberOfGoodsLoaders; i++){
if (GoodsLoaderBusy[i] == false){
waitingForRestock[restockRequestNumber].myDept=deptNum;
printf("DepartmentSalesman [%d]  is helping Customer [%d]  and informs the GoodsLoader [%d] that [%d] is out of stock.\n",salesNum,restockRequestNumber,i,waitingForRestock[restockRequestNumber].requestedItem );
waitingForRestock[restockRequestNumber].goodsLoaderHandler = i;
GoodsLoaderBusy[i] = true;   
GLFound=true;
GoodsLoadersCondition[i]->Signal(GLLock);//wake up goodsloader


goodsloadernumber=i; 
break;}

}
printf("DepartmentSalesman [%d] of Department [%d] release lock on the GoodsLoader [%d].\n",salesNum,deptNum,goodsloadernumber);

GLLock->Release();
currentThread->Yield();
departmentLock[deptNum]->Release();
}


//need to know which cust is waiting 
//customer that said item needed restock should already be waiting
//SalesmanCondition[deptNum][salesNum]->Wait(salesmanLock[deptNum][salesNum]);
}



//check if any restocking is done and signal cust



salesmanNumOfCustomers[deptNum][salesNum]--;
CustomerCondition[waitingForRestock[restockRequestNumber].CustNum]->Signal(salesmanLock[deptNum][salesNum]);
//deptLineLock[deptNum]->Release();
}
SalesmanCondition[deptNum][salesNum]->Wait(salesmanLock[deptNum][salesNum]);

for(int i = 0; i < numberOfCustomers; i++){

if (waitingForRestock[i].salesHandler == salesNum && waitingForRestock[i].glFinished == true && waitingForRestock[i].myDept == deptNum){
printf("DepartmentSalesman [%d] of Department [%d] is informed by the GoodsLoader [%d] that [%d] is restocked.\n",salesNum,deptNum,waitingForRestock[i].goodsLoaderHandler,waitingForRestock[i].requestedItem);
//waitingForRestock[i].goodsLoaderHandler = -1;
printf("DepartmentSalesman [%d] of Department [%d] informs the Customer/PrivilegeCustomer [%d] that [%d] is restocked.\n",salesNum,deptNum,i,waitingForRestock[i].requestedItem);
waitingForRestock[i].glFinished=false;
 CustomerCondition[i]->Signal(salesmanLock[deptNum][salesNum]);


}
}

ReadySalesman[deptNum][salesNum]=true;


for(int i = 0; i < numberOfCustomers; i++){//see if any customer needs a restock

if (waitingForRestock[i].needHelp == true && waitingForRestock[i].myDept == deptNum){
printf("DepartmentSalesman [%d] of Department [%d] is informed by Customer/PrivilegeCustomer [%d] that [%d] is out of stock.\n",salesNum,deptNum, waitingForRestock[i].CustNum,waitingForRestock[i].requestedItem); 
waitingForRestock[i].salesHandler = salesNum;


salesmanNumOfCustomers[deptNum][salesNum]++;
}
}
ReadySalesman[deptNum][salesNum]=false;


}
}
}


 
//main initialization function 
void SupermarketSimulation(){
Thread *t;
char *name;
int i;
int rando;
srand(time(NULL));
priv = true;
activeCustomers = numberOfCustomers;
int numberOfPriveledged = numberOfCustomers / 2;

printf("Number of Cashiers = [%d]\n",numberOfCashiers);
printf("Number of Goods Loaders = [%d]\n", numberOfGoodsLoaders);
printf("Number of PriviledgedCustomers = [%d]\n",numberOfPriveledged);
printf("Number of Customers = [%d]\n",numberOfCustomers);
printf("Number of Managers = [1]\n");

  totalSalesman = numberOfSalesmanA + numberOfSalesmanB + numberOfSalesmanC + numberOfSalesmanD + numberOfSalesmanE;

printf("Number of DepartmentSalesmen = [%d]\n",totalSalesman);

if (!test[1]){

printf("Items:\n");
//initialize total items
for(i=0;i<5;i++){
    for(int j = 0; j<10;j++){
     deptItems[i][j] = GetRand(minNumberOfItems,maxNumberOfItems);
printf("Dept %d has %d of item # %d which costs $ %d\n",i,deptItems[i][j],j,(j+1));
 }
}
}


        


totalSales = 0;

numberOfItemsReturns = 0;

for(i = 0;i<numberOfDepartments;i++){
        for(int j = 0; j < numberOfSalesman[i]; j++){
                 salesOnBreak[i][j] = false;
                                 }
  }

for(i = 0;i<numberOfDepartments;i++){
        for(int j = 0; j < numberOfSalesman[i]; j++){
                 salesmanNumOfCustomers[i][j] = 0;
                                 }
  }
for(i = 0; i<numberOfCashiers;i++)
cashTotal[i] = 0;

for(i=0;i<5;i++){//initialize dept line lengths to zero
 deptLineLength[i]=0;
}

for( i=0; i<numberOfDepartments; i++){
        for(int j=0; j<5; j++)
ReadySalesman[i][j]=false;
}

for(i = 0; i < numberOfCustomers; i++){
waitingForRestock[i].needHelp = false;
waitingForRestock[i].glFinished = false;
waitingForRestock[i].needsGL = false;
}

for(i = 0; i < numberOfGoodsLoaders; i++)
usingStockRoom[i] = false;

for(i = 0; i< numberOfCustomers; i++)
cashierHelpingCustomer[i] = -1;
  
//initialize numberofdepartments with number of salesman per dept
for(i=0; i<5;i++){
        if(i==0)
        numberOfSalesman[i]=numberOfSalesmanA;
        if(i==1)
        numberOfSalesman[i]=numberOfSalesmanB;
        if(i==2)
        numberOfSalesman[i]=numberOfSalesmanC;
        if(i==3)
        numberOfSalesman[i]=numberOfSalesmanD;
        if(i==4)
        numberOfSalesman[i]=numberOfSalesmanE;
        
        }
        
//****randomly initialize number of items in each dept***



for(i = 0; i < numberOfDepartments; i++)
initialSalesman[i] = -1;


for(i = 0;i<numberOfCustomers;i++){
returns[i] = false;
}
/*
for(i = 0; i<numberOfCustomers; i++
List *waitingForRestockList[numberOfDepartments];//list of customers waiting for restock in a dept
*/

for(i=0; i < numberOfCustomers; i++){//DIFED initialization of priveleged
 priveleged[i] = false;//DIFED
  
  }//DIFEd
  for(i=0; i<numberOfCashiers; i++)
  OperationalLine[i]=true;
  
  
  
  for(i = 0; i < numberOfCashiers;i++)
  cashBusy[i] = false;

  
for(i=1; i<numberOfCashiers; i++)//DIFED initialization of breaks
OnBreak[i]=false;

for(i=0; i<numberOfCustomers; i++)
CustomerFinished[i]=false;

for(i=0; i<numberOfCashiers;i++)
privelegedLinesList[i] = new List();

for(i=0;i < numberOfCashiers;i++)
cashierLinesList[i] = new List();

for(i=0;i < 5;i++){
cashierLinesList[i] = new List();
}

for(i=0;i<5;i++)
deptLineList[i]= new List();//line list for departments

for(i = 0; i < numberOfCustomers; i++){//so all the customers initially dont need help
custNeedHelp[i] = false;

}

for(i=0; i<numberOfCustomers; i++){//initialize enought money to zero
enoughMoney[i]=true;
}
//set Cashier line lengths to zero
for(i = 0; i < numberOfCashiers; i++)
cashLineLengths[i] = 0;


//initialize that no items need to be restocked
for(i=0;i<5;i++)
 deptItemsNeedRestock[i] = false;

for(i=0;i<numberOfGoodsLoaders; i++)
GoodsLoaderBusy[i] = false;



//****** Create Locks ************

initializeLock= new Lock("Customer Initialize Lock");
managerLock = new Lock("ManagerLock");
GLLock = new Lock("Goods Loader lock");
privelegedLineLock = new Lock("privelegedLine");//priveleged line lock
cashierLineLock = new Lock("CashierLine");
totalSalesLock = new Lock("SalesLock");//krump
returnsLock = new Lock("Returns");
storeRoomLock = new Lock("StoreRoom");

trollyLineLock = new Lock("TrollyLine");
generatorLock = new Lock("GeneratorLock");



for(i=0;i<numberOfDepartments; i++){
        for(int j=0; j<numberOfSalesman[i]; j++)
salesmanLock[i][j] = new Lock("Salesman Lock");

}
for(i=0;i<numberOfDepartments; i++){
departmentLock[i] = new Lock("Department Lock");

}

for(i=0;i<5; i++)
deptItemLock[i] = new Lock("Item Lock");


for(i=0;i<5;i++)
deptLineLock[i] = new Lock("ALINELOCK");

for(i=0;i<numberOfCustomers;i++)
customerLock[i] = new Lock("CUST LOCK");


operationalLineLock = new Lock("OPLINELOCK");

//Cashier - Customer Relation Locks
for(i = 0; i < numberOfCashiers; i++) {
    name = new char[15];
    cashierLock[i] = new Lock(name);
  }
  
  //GoodsLoader Lock
for(i = 0; i < numberOfGoodsLoaders; i++) {
    name = new char[15];
   goodsLoaderLock[i] = new Lock(name);
  }


//********  Create Condition Variables ********

        name = new char [15];
    ManagerCondition = new Condition(name);

for(i = 0; i < numberOfCustomers; i++) {
    name = new char [15];
    CustomerCondition[i] = new Condition(name);
  }


for(i = 0; i < numberOfCashiers; i++) {
    name = new char [15];
    CashierCondition[i] = new Condition(name);
  }


for(i = 0; i < numberOfGoodsLoaders; i++) {
    name = new char [15];
    GoodsLoadersCondition[i] = new Condition(name);
  }
  
for( i =0; i<numberOfCustomers ; i++){
        waitingForRestock[i].goodsLoaderHandler=-1;
}
for(i = 0;i<numberOfDepartments;i++){
        for(int j = 0; j < numberOfSalesman[i]; j++){
                 name = new char[15];
                
                 SalesmanCondition[i][j] = new Condition(name);
                                 }
  }


//*******  Create All Threads *******

 //Create the Salesman
  for(i = 0;i<numberOfDepartments;i++){
        for(int j = 0; j < numberOfSalesman[i]; j++){
                 name = new char[15];
                 printf("Dept %d Salesman %d Created.\n", i, j);
                 t = new Thread(name);
                 t->Fork((VoidFunctionPtr)Salesman,i);
                                 }
  }

  // Create the GoodsLoaders
  for(i=0; i < numberOfGoodsLoaders; i++) {
    name = new char[15];
    //printf("GoodsLoader number %d created.\n",i);
    t = new Thread(name);
    t->Fork((VoidFunctionPtr)GoodsLoader,i);
  }

// Create the Manager
name = new char[15];
//printf("Manager Created\n");
t = new Thread(name);
t->Fork((VoidFunctionPtr)Manager,0);


//create the customers

  
  // Create the Cashiers
  for(i=0; i < numberOfCashiers; i++) {
    name = new char[15];
    printf("Cashier number %d created.\n",i);
    t = new Thread(name);
    t->Fork((VoidFunctionPtr)Cashier,i);
  }
  
  
 
  
  
 
 //create the customers
   for(i=0; i < numberOfCustomers; i++) {//DIFED
    name = new char[15];
    //printf("Customer number %d created.\n",i);
    t = new Thread(name);
        
        if(priv==true)
        priv=false;
        else
        priv=true;
        
        if(priv==true){
        priveleged[i]=true;
       // numberOfPriveleged++;
        
        }
    t->Fork((VoidFunctionPtr)Customer,i);
  }
  
  
  
  
 
  
  
  
  

  
 
  

}



//************ TEST CODE ******************
void Test1(){
//shortest line test
//Customers always take the shortest line,
//but no 2 customers ever choose the same shortest line at the same time

for(int i = 0;i<11;i++)
test[i] = false;
printf("Starting Test 1\n");
test[1] = true;
SupermarketSimulation();

}

void Test2(){
//Managers can only talk to one Cashier, or one Customer, at a time

//put print statements in manager... only executes if someone doesnt have enough money

for(int i = 0;i<11;i++)
test[i] = false;
printf("Starting Test 2\n");
test[2] = true;
SupermarketSimulation();

}


void Test3(){
//Customers do not leave until they are given their receipt by the Cashier. 
//The Cashier does not start on another customer until they know that the last Customer has left their area

for(int i = 0;i<11;i++)
test[i] = false;
printf("Starting Test 3\n");
test[3] = true;
SupermarketSimulation();

}
void Test4(){
//Cashier scans the items till the trolly is empty

for(int i = 0;i<11;i++)
test[i] = false;
printf("Starting Test 4\n");
test[4] = true;
SupermarketSimulation();

}
void Test5(){
//Cashiers are sent on break by the Manager randomly.


for(int i = 0;i<11;i++)
test[i] = false;
printf("Starting Test 5\n");
test[5] = true;
SupermarketSimulation();

}
void Test6(){
//Managers get Cashiers off their break when lines have 3, 
//or more, Customers

for(int i = 0;i<11;i++)
test[i] = false;
printf("Starting Test 6\n");
test[6] = true;
SupermarketSimulation();

}
void Test7(){
//Total sales never suffers from a race condition

for(int i = 0;i<11;i++)
test[i] = false;
printf("Starting Test 7\n");
test[7] = true;
SupermarketSimulation();


}
void Test8(){
//Goods Loader don't try to restock an item on a shelf 
//when a Customer is trying to take an item off the shelf

for(int i = 0;i<11;i++)
test[i] = false;
printf("Starting Test 8\n");
test[8] = true;
SupermarketSimulation();

}
void Test9(){
//Only one Goods Loader enters the stock room at a time.


for(int i = 0;i<11;i++)
test[i] = false;
printf("Starting Test 9\n");
test[9] = true;
SupermarketSimulation();


}
void Test10(){
//Customers wait for items to be
//restocked - when told by the Department Salesman


for(int i = 0;i<11;i++)
test[i] = false;
printf("Starting Test 10\n");
test[10] = true;
SupermarketSimulation();

}





//----------------------------------------------------------------------
// ThreadTest
//      Set up a ping-pong between two threads, by forking a thread 
//      to call SimpleThread, and then calling SimpleThread ourselves.
//----------------------------------------------------------------------




// --------------------------------------------------
// Test Suite
// --------------------------------------------------


// --------------------------------------------------
// Test 1 - see TestSuite() for details
// --------------------------------------------------
Semaphore t1_s1("t1_s1",0);       // To make sure t1_t1 acquires the
                                  // lock before t1_t2
Semaphore t1_s2("t1_s2",0);       // To make sure t1_t2 Is waiting on the 
                                  // lock before t1_t3 releases it
Semaphore t1_s3("t1_s3",0);       // To make sure t1_t1 does not release the
                                  // lock before t1_t3 tries to acquire it
Semaphore t1_done("t1_done",0);   // So that TestSuite knows when Test 1 is
                                  // done
Lock t1_l1("t1_l1");              // the lock tested in Test 1

// --------------------------------------------------
// t1_t1() -- test1 thread 1
//     This is the rightful lock owner
// --------------------------------------------------
void t1_t1() {
    t1_l1.Acquire();
    t1_s1.V();  // Allow t1_t2 to try to Acquire Lock
 
    printf ("%s: Acquired Lock %s, waiting for t3\n",currentThread->getName(),
            t1_l1.getName());
    t1_s3.P();
    printf ("%s: working in CS\n",currentThread->getName());
    for (int i = 0; i < 1000000; i++) ;
    printf ("%s: Releasing Lock %s\n",currentThread->getName(),
            t1_l1.getName());
    t1_l1.Release();
    t1_done.V();
}

// --------------------------------------------------
// t1_t2() -- test1 thread 2
//     This thread will wait on the held lock.
// --------------------------------------------------
void t1_t2() {

    t1_s1.P();  // Wait until t1 has the lock
    t1_s2.V();  // Let t3 try to acquire the lock

    printf("%s: trying to acquire lock %s\n",currentThread->getName(),
            t1_l1.getName());
    t1_l1.Acquire();

    printf ("%s: Acquired Lock %s, working in CS\n",currentThread->getName(),
            t1_l1.getName());
    for (int i = 0; i < 10; i++)
        ;
    printf ("%s: Releasing Lock %s\n",currentThread->getName(),
            t1_l1.getName());
    t1_l1.Release();
    t1_done.V();
}

// --------------------------------------------------
// t1_t3() -- test1 thread 3
//     This thread will try to release the lock illegally
// --------------------------------------------------
void t1_t3() {

    t1_s2.P();  // Wait until t2 is ready to try to acquire the lock

    t1_s3.V();  // Let t1 do it's stuff
    for ( int i = 0; i < 3; i++ ) {
        printf("%s: Trying to release Lock %s\n",currentThread->getName(),
               t1_l1.getName());
        t1_l1.Release();
    }
}

// --------------------------------------------------
// Test 2 - see TestSuite() for details
// --------------------------------------------------
Lock t2_l1("t2_l1");            // For mutual exclusion
Condition t2_c1("t2_c1");       // The condition variable to test
Semaphore t2_s1("t2_s1",0);     // To ensure the Signal comes before the wait
Semaphore t2_done("t2_done",0);     // So that TestSuite knows when Test 2 is
                                  // done

// --------------------------------------------------
// t2_t1() -- test 2 thread 1
//     This thread will signal a variable with nothing waiting
// --------------------------------------------------
void t2_t1() {
    t2_l1.Acquire();
    printf("%s: Lock %s acquired, signalling %s\n",currentThread->getName(),
           t2_l1.getName(), t2_c1.getName());
    t2_c1.Signal(&t2_l1);
    printf("%s: Releasing Lock %s\n",currentThread->getName(),
           t2_l1.getName());
    t2_l1.Release();
    t2_s1.V();  // release t2_t2
    t2_done.V();
}

// --------------------------------------------------
// t2_t2() -- test 2 thread 2
//     This thread will wait on a pre-signalled variable
// --------------------------------------------------
void t2_t2() {
    t2_s1.P();  // Wait for t2_t1 to be done with the lock
    t2_l1.Acquire();
    printf("%s: Lock %s acquired, waiting on %s\n",currentThread->getName(),
           t2_l1.getName(), t2_c1.getName());
    t2_c1.Wait(&t2_l1);
    printf("%s: Releasing Lock %s\n",currentThread->getName(),
           t2_l1.getName());
    t2_l1.Release();
}
// --------------------------------------------------
// Test 3 - see TestSuite() for details
// --------------------------------------------------
Lock t3_l1("t3_l1");            // For mutual exclusion
Condition t3_c1("t3_c1");       // The condition variable to test
Semaphore t3_s1("t3_s1",0);     // To ensure the Signal comes before the wait
Semaphore t3_done("t3_done",0); // So that TestSuite knows when Test 3 is
                                // done

// --------------------------------------------------
// t3_waiter()
//     These threads will wait on the t3_c1 condition variable.  Only
//     one t3_waiter will be released
// --------------------------------------------------
void t3_waiter() {
    t3_l1.Acquire();
    t3_s1.V();          // Let the signaller know we're ready to wait
    printf("%s: Lock %s acquired, waiting on %s\n",currentThread->getName(),
           t3_l1.getName(), t3_c1.getName());
    t3_c1.Wait(&t3_l1);
    printf("%s: freed from %s\n",currentThread->getName(), t3_c1.getName());
    t3_l1.Release();
    t3_done.V();
}


// --------------------------------------------------
// t3_signaller()
//     This threads will signal the t3_c1 condition variable.  Only
//     one t3_signaller will be released
// --------------------------------------------------
void t3_signaller() {

    // Don't signal until someone's waiting
    
    for ( int i = 0; i < 5 ; i++ ) 
        t3_s1.P();
    t3_l1.Acquire();
    printf("%s: Lock %s acquired, signalling %s\n",currentThread->getName(),
           t3_l1.getName(), t3_c1.getName());
    t3_c1.Signal(&t3_l1);
    printf("%s: Releasing %s\n",currentThread->getName(), t3_l1.getName());
    t3_l1.Release();
    t3_done.V();
}
 
// --------------------------------------------------
// Test 4 - see TestSuite() for details
// --------------------------------------------------
Lock t4_l1("t4_l1");            // For mutual exclusion
Condition t4_c1("t4_c1");       // The condition variable to test
Semaphore t4_s1("t4_s1",0);     // To ensure the Signal comes before the wait
Semaphore t4_done("t4_done",0); // So that TestSuite knows when Test 4 is
                                // done

// --------------------------------------------------
// t4_waiter()
//     These threads will wait on the t4_c1 condition variable.  All
//     t4_waiters will be released
// --------------------------------------------------
void t4_waiter() {
    t4_l1.Acquire();
    t4_s1.V();          // Let the signaller know we're ready to wait
    printf("%s: Lock %s acquired, waiting on %s\n",currentThread->getName(),
           t4_l1.getName(), t4_c1.getName());
    t4_c1.Wait(&t4_l1);
    printf("%s: freed from %s\n",currentThread->getName(), t4_c1.getName());
    t4_l1.Release();
    t4_done.V();
}


// --------------------------------------------------
// t2_signaller()
//     This thread will broadcast to the t4_c1 condition variable.
//     All t4_waiters will be released
// --------------------------------------------------
void t4_signaller() {

    // Don't broadcast until someone's waiting
    
    for ( int i = 0; i < 5 ; i++ ) 
        t4_s1.P();
    t4_l1.Acquire();
    printf("%s: Lock %s acquired, broadcasting %s\n",currentThread->getName(),
           t4_l1.getName(), t4_c1.getName());
    t4_c1.Broadcast(&t4_l1);
    printf("%s: Releasing %s\n",currentThread->getName(), t4_l1.getName());
    t4_l1.Release();
    t4_done.V();
}
// --------------------------------------------------
// Test 5 - see TestSuite() for details
// --------------------------------------------------
Lock t5_l1("t5_l1");            // For mutual exclusion
Lock t5_l2("t5_l2");            // Second lock for the bad behavior
Condition t5_c1("t5_c1");       // The condition variable to test
Semaphore t5_s1("t5_s1",0);     // To make sure t5_t2 acquires the lock after
                                // t5_t1

// --------------------------------------------------
// t5_t1() -- test 5 thread 1
//     This thread will wait on a condition under t5_l1
// --------------------------------------------------
void t5_t1() {
    t5_l1.Acquire();
    t5_s1.V();  // release t5_t2
    printf("%s: Lock %s acquired, waiting on %s\n",currentThread->getName(),
           t5_l1.getName(), t5_c1.getName());
    t5_c1.Wait(&t5_l1);
    printf("%s: Releasing Lock %s\n",currentThread->getName(),
           t5_l1.getName());
    t5_l1.Release();
}

// --------------------------------------------------
// t5_t1() -- test 5 thread 1
//     This thread will wait on a t5_c1 condition under t5_l2, which is
//     a Fatal error
// --------------------------------------------------
void t5_t2() {
    t5_s1.P();  // Wait for t5_t1 to get into the monitor
    t5_l1.Acquire();
    t5_l2.Acquire();
    printf("%s: Lock %s acquired, signalling %s\n",currentThread->getName(),
           t5_l2.getName(), t5_c1.getName());
    t5_c1.Signal(&t5_l2);
    printf("%s: Releasing Lock %s\n",currentThread->getName(),
           t5_l2.getName());
    t5_l2.Release();
    printf("%s: Releasing Lock %s\n",currentThread->getName(),
           t5_l1.getName());
    t5_l1.Release();
}

// --------------------------------------------------
// TestSuite()
//     This is the main thread of the test suite.  It runs the
//     following tests:
//
//       1.  Show that a thread trying to release a lock it does not
//       hold does not work
//
//       2.  Show that Signals are not stored -- a Signal with no
//       thread waiting is ignored
//
//       3.  Show that Signal only wakes 1 thread
//
//       4.  Show that Broadcast wakes all waiting threads
//
//       5.  Show that Signalling a thread waiting under one lock
//       while holding another is a Fatal error
//
//     Fatal errors terminate the thread in question.
// --------------------------------------------------
void ThreadTest() {
    Thread *t;
    char *name;
    int i;
    

    
    
    int number_run;
  cout << "Enter a test number" << endl;
  cout << "0. Entire Simulation" << endl;
  cout << "1. RUN TEST 1" << endl;
  cout << "2. RUN TEST 2" << endl;
  cout << "3. RUN TEST 3" << endl;
  cout << "4. RUN TEST 4" << endl;
  cout << "5. RUN TEST 5" << endl;
  cout << "6. RUN TEST 6" << endl;
  cout << "7. RUN TEST 7" << endl;
  cout << "8. RUN TEST 8" << endl;
  cout << "9. RUN TEST 9" << endl;
  cout << "10. RUN TEST 10" << endl;
  cout << "11. RUN TEST TO TEST PART 1" << endl;

  cin >> number_run;
  if(number_run == 0)
    SupermarketSimulation();
  else if(number_run == 1)
    Test1();
 else if(number_run == 2)
    Test2();
 else if(number_run == 3)
    Test3();
  else if(number_run == 4)
    Test4();
 else if(number_run == 5)
    Test5();
 else if(number_run == 6)
    Test6();
 else if(number_run == 7)
    Test7();
 else if(number_run == 8)
    Test8();
 else if(number_run == 9)
    Test9();
else  if(number_run == 10)
    Test10();
    
  


else{
    
        
        
        
        
    // Test 1

    printf("Starting Test 1\n");

    t = new Thread("t1_t1");
    t->Fork((VoidFunctionPtr)t1_t1,0);

    t = new Thread("t1_t2");
    t->Fork((VoidFunctionPtr)t1_t2,0);

    t = new Thread("t1_t3");
    t->Fork((VoidFunctionPtr)t1_t3,0);

    // Wait for Test 1 to complete
    for (  i = 0; i < 2; i++ )
        t1_done.P();

    // Test 2

    printf("Starting Test 2.  Note that it is an error if thread t2_t2\n");
    printf("completes\n");

    t = new Thread("t2_t1");
    t->Fork((VoidFunctionPtr)t2_t1,0);

    t = new Thread("t2_t2");
    t->Fork((VoidFunctionPtr)t2_t2,0);

    // Wait for Test 2 to complete
    t2_done.P();

    // Test 3

    printf("Starting Test 3\n");

    for (  i = 0 ; i < 5 ; i++ ) {
        name = new char [20];
        sprintf(name,"t3_waiter%d",i);
        t = new Thread(name);
        t->Fork((VoidFunctionPtr)t3_waiter,0);
    }
    t = new Thread("t3_signaller");
    t->Fork((VoidFunctionPtr)t3_signaller,0);

    // Wait for Test 3 to complete
    for (  i = 0; i < 2; i++ )
        t3_done.P();

    // Test 4

    printf("Starting Test 4\n");

    for (  i = 0 ; i < 5 ; i++ ) {
        name = new char [20];
        sprintf(name,"t4_waiter%d",i);
        t = new Thread(name);
        t->Fork((VoidFunctionPtr)t4_waiter,0);
    }
    t = new Thread("t4_signaller");
    t->Fork((VoidFunctionPtr)t4_signaller,0);

    // Wait for Test 4 to complete
    for (  i = 0; i < 6; i++ )
        t4_done.P();

    // Test 5

    printf("Starting Test 5.  Note that it is an error if thread t5_t1\n");
    printf("completes\n");

    t = new Thread("t5_t1");
    t->Fork((VoidFunctionPtr)t5_t1,0);

    t = new Thread("t5_t2");
    t->Fork((VoidFunctionPtr)t5_t2,0);

}}